package net.chowda.castcluster.util;

import org.apache.commons.httpclient.HttpConnection;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.StatusLine;
import org.apache.commons.httpclient.methods.GetMethod;

import java.io.*;
import java.util.GregorianCalendar;
import java.util.Date;
import java.util.Calendar;

/**
 * wrap GetMethod with some caching logic.
 *
 * TODO - make this configurable?
 */
public class CachedGetMethod extends GetMethod {
    // number of hours to cache files for.
    private static final int CACHE_HOURS = -2;

    public CachedGetMethod() {
        super();
    }

    public CachedGetMethod(String string) {
        super(string);
    }

    public int execute(HttpState httpState, HttpConnection httpConnection) throws IOException {
        int status = 200;

        String urlFile = urlToFileName(getURI().toString());
        String baseDir = CastClusterConfig.getInstance().getGlobalProp(CastClusterConfig.CONFIG_BASE_DIR);
        File cacheFile = new File(baseDir + "/cache/" + urlFile);
        if(!cacheFile.exists()) {
            status = fetchFileToCache(cacheFile, httpState, httpConnection);
        } else {
            GregorianCalendar now = new GregorianCalendar();
            GregorianCalendar then = new GregorianCalendar();
            then.setTime(new Date(cacheFile.lastModified()));
            now.add(Calendar.HOUR_OF_DAY, CACHE_HOURS);
            // this file is more than 2 hours old, refetch.
            if(then.before(now)) {
                status = fetchFileToCache(cacheFile, httpState, httpConnection);
            }
        }
        setResponseStream(new FileInputStream(cacheFile));

        return status;
    }

    private int fetchFileToCache(File cacheFile, HttpState httpState, HttpConnection httpConnection) throws IOException {
        int status;
        cacheFile.getParentFile().mkdirs();
        status = super.execute(httpState, httpConnection);
        InputStream response = getResponseBodyAsStream();
        FileOutputStream out = new FileOutputStream(cacheFile);
        int count;
        byte[] b = new byte[2048];
        while((count = response.read(b)) > -1) {
            out.write(b, 0, count);
        }
        out.close();
        return status;
    }

    public int getStatusCode() {
        if(getStatusLine() != null) return super.getStatusCode();
        return 200;
    }

    private static String urlToFileName(String playListName) {
        StringBuilder id = new StringBuilder(playListName.length());
        char[] chars = playListName.toCharArray();
        for (char aChar : chars) {
            id.append(Character.isLetterOrDigit(aChar) ? aChar : '_');
        }
        return id.toString();
    }

}
